class FeatureNode extends MyNode{
    constructor($state='new',...obj){
        super('Feature',$state,{
            name:"特征名称",
            opertion:"特征函数",
            type:"auto",
            outId:0,
            params:[],
            $faults:new Set(),
            $reasons:new Set(),
            $issues:new Set(),
            $solutions:new Set(),
            $featureType:null,
            frequency:{}
        },...obj);
        this.params.forEach((param,index)=>{
            if(param && param.low != null){
                this.params[index] = param.low;
            }
        },this);

        this.quantum = this.defaultQuantum();
    }

    isAuto(){
        return this.type=='auto';
    }

    defaultQuantum(){
        if (this.quantum instanceof Object){
            this.quantum = this.quantum.low;
        }
        return this.quantum || 100;
    }

    defaultFrequency(faultId){
        let df = {};
        df[`${faultId}`] = 0;
        delete this.frequency["undefined"];
        return $.extend(true,df,this.frequency);
    }

    totalFrequency(){
        let dfs = this.frequency || {};
        return Object.keys(dfs).map(key=>dfs[key]).reduce((x,y)=>eval(x)+eval(y),0);
    }

    getFaults(){
        return _.uniqBy([... this.$faults], f=>f.id);
    }

    getReasons() {
        return [... (this.$reasons || [])]
    }

    getIssues() {
        return [... (this.$issues || [])]
    }

    getMaxIssueString(g) {
        return RunningIssueNode.asString([... (this.$issues || [])]
            .map(i=>g.getNode(i).suggest)
            .map(str=>RunningIssueNode.asInt(str))
            .reduce((x,y)=>x>y?x:y,0));
    }

    getSolutions() {
        return [... (this.$solutions || [])]
    }

    getTemplate(edge,g){
        return `
 <div class="form-group">
    <label class="col-sm-2 control-label">导出ID</label>
    <div class="col-sm-10">
        <input data-ng-model-options="{updateOn:'default blur',debounce:{default:5000,blur:0}}" type="text" class="form-control" data-ng-model="graph.getNode('${this.id}').outId" placeholder="用于导出的ID">
    </div>
 </div>
 <div class="form-group">
    <label class="col-sm-2 control-label">判断方式</label>
    <div class="col-sm-10">
    <select class="col-sm-10 form-control" data-ng-model="graph.getNode('${this.id}').type" data-ng-options="md.v as md.k for md in [{k:'机器判断',v:'auto'},{k:'人工判断',v:'manual'}]"></select>
    </div>
 </div>
 <div data-ng-show="graph.getNode('${this.id}').isAuto()" class="form-group">
    <label class="col-sm-2 control-label">特征类别</label>
    <div class="col-sm-10">
        <div class="input-group">
            <span class="input-group-addon">
                <select data-ng-model="graph.getNode('${this.id}').$featureType" data-ng-options="type as type.name for type in featureTypes" ng-change="graph.getNode('${this.id}').name=graph.getNode('${this.id}').$featureType.name" ></select>
            </span>
            <input data-ng-model-options="{updateOn:'default blur',debounce:{default:5000,blur:0}}" type="text" class="form-control" data-ng-model="graph.getNode('${this.id}').name" placeholder="请输入名称">
        </div>
    </div>
 </div>
 <div data-ng-show="graph.getNode('${this.id}').isAuto()" class="form-group">
    <label class="col-sm-2 control-label">特征函数</label>
    <div class="col-sm-10">
    <div class="input-group">
            <span class="input-group-addon">
                <select data-ng-model="$opertion" data-ng-options="type as type.name for type in methodTypes" ng-change="setMethodType(graph.getNode('${this.id}'),$opertion)" ></select>
            </span>
    <input data-ng-model-options="{updateOn:'default blur',debounce:{default:5000,blur:0}}" type="text" class="form-control" data-ng-model="graph.getNode('${this.id}').opertion" placeholder="请输入函数名称">
        </div>
    </div>
 </div>
 <div data-ng-show="graph.getNode('${this.id}').isAuto()" class="form-group">
    <label class="col-sm-2 control-label">固定参数列&nbsp;<a href="#" ng-click="appendArgv('${this.id}')">补充参数</a></label>
    <ol class="col-sm-10 form-control-static">
      <li ng-repeat="param in graph.getNode('${this.id}').params track by $index">
        <input class="form-control col-sm-8" ng-model-options="{updateOn: 'blur'}" ng-model="graph.getNode('${this.id}').params[$index]" placeholder="参数值">
        <a class="form-control-static col-sm-2" href="#" ng-click="removeArgv('${this.id}',$index)">删除参数</a><br>
      </li>
    </ol>
 </div>
 <div class="form-group">
    <label class="col-sm-2 control-label">特征描述</label>
    <div class="col-sm-10">
    <textarea data-ng-model-options="{updateOn:'default blur',debounce:{default:5000,blur:0}}" rows="3" class="col-sm-10 form-control" data-ng-model="graph.getNode('${this.id}').description" placeholder="请输入特征描述"></textarea>
    </div>
 </div>
 <div class="form-group" ng-if="graph.getNode('${this.id}').$is_sub_graph">
    <label class="col-sm-2 control-label">置信度</label>
    <div class="col-sm-10">
    <table class="table table-responsive table-bordered">
    <thead>
        <tr><td>所属故障</td><td>频率</td><td>置信度</td></tr>
    </thead>
    <tbody ng-init="graph.getNode('${this.id}').quantum = graph.getNode('${this.id}').defaultQuantum(); graph.getNode('${this.id}').frequency = graph.getNode('${this.id}').defaultFrequency(graph.getRoot().id); ">
        <tr ng-repeat="ft in graph.getNode('${this.id}').getFaults() track by ft.id">
        <td>{{ft.getText()}}</td>
        <td>{{graph.getNode('${this.id}').frequency[ft.id] || 0}}</td>
        <td>{{((graph.getNode('${this.id}').frequency[ft.id] || 0) / graph.getNode('${this.id}').defaultQuantum() * 100).toFixed(2)}}%</td>
        </tr>
    </tbody>
    <tfoot>
        <tr><td>总和</td><td>{{graph.getNode('${this.id}').totalFrequency()}}</td>
        <td>{{(graph.getNode('${this.id}').totalFrequency() / graph.getNode('${this.id}').defaultQuantum() *100).toFixed(2)}}%</td></tr>
        <tr><td>可分配</td><td>{{graph.getNode('${this.id}').defaultQuantum() - graph.getNode('${this.id}').totalFrequency()}}</td>
        <td>{{((graph.getNode('${this.id}').defaultQuantum() - graph.getNode('${this.id}').totalFrequency()) / graph.getNode('${this.id}').defaultQuantum() * 100).toFixed(2)}}%</td></tr>
    </tfoot>
    </table>
    请输入对当前的故障分配初始频率(应小于等于可分配的数量)：
    <input  ng-change="frequencyUpdated('${this.id}')"  ng-model="graph.getNode('${this.id}').frequency[graph.getRoot().id]" data-ng-model-options="{updateOn:'default blur',debounce:{default:5000,blur:0}}">
    </div>
</div>

 <br>
 <div class="form-group" ng-if="graph.getNode('${this.id}').$is_sub_graph2">
    <label class="col-sm-2 control-label">对原因的置信度</label>
    <div class="col-sm-10">
    <table class="table table-responsive table-bordered">
    <thead>
        <tr>
            <td>原因ID</td>
            <td>所属原因</td>
            <td>置信度</td>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="rid in graph.getNode('${this.id}').getReasons('${this.id}')" >
        <td>{{rid}}</td>
        <td>{{graph.getNode(rid).getText()}}</td>
        <td ng-init="graph.getNode(rid).frequency = graph.getNode(rid).defaultFrequency();">
        <input  
          ng-model="graph.getNode(rid).frequency['${this.id}']" 
          data-ng-model-options="{updateOn:'default blur',debounce:{default:5000,blur:0}}">
        </td>
        </tr>
    </tbody>
    </table>
    </div>
</div>

<br>
 <div class="form-group" ng-if="graph.getNode('${this.id}').$is_sub_graph3">
    <label class="col-sm-2 control-label">关联到的运行建议</label>
    <p class="col-sm-10 form-control-static">{{graph.getNode('${this.id}').getMaxIssueString(graph)}}</p>
</div>

<br>
 <div class="form-group" ng-if="graph.getNode('${this.id}').$is_sub_graph4">
    <label class="col-sm-2 control-label">对解决方案的置信度</label>
    <div class="col-sm-10">
    <table class="table table-responsive table-bordered">
    <thead>
        <tr><td>解决方案</td><td>置信度</td></tr>
    </thead>
    <tbody>
        <tr ng-repeat="rid in graph.getNode('${this.id}').getSolutions('${this.id}')" >
        <td>{{graph.getNode(rid).getText()}}</td>
        <td ng-init="graph.getNode(rid).frequency = graph.getNode(rid).defaultFrequency();">
        <input  
          ng-model="graph.getNode(rid).frequency['${this.id}']" 
          data-ng-model-options="{updateOn:'default blur',debounce:{default:5000,blur:0}}">
        </td>
        </tr>
    </tbody>
    </table>
    </div>
</div>

 <br>
 <div class="form-group">
 <label class="col-sm-2 control-label">操作</label>
 <p class="col-sm-10 form-control-static">
     <a class="btn" data-ng-if="allowComponent('${this.id}')" data-ng-click="attachComponent('${this.id}')">添加测点位置</a>
     <a class="btn" data-ng-if="allowComponent('${this.id}')" data-ng-click="attachGroup('${this.id}','ComponentGroup')">添加元件组</a>
     <a class="btn" href="javascript:;" ng-click="removeEdge(${edge})">删除当前节点</a>
 </p>
</div>
`;
    }

    getReadonlyTemplate(edge,g){
        return `
 <div class="form-group">
    <label class="col-sm-2 control-label">判断方式</label>
    <p class="col-sm-10 form-control-static">${this.type=='auto'?'机器判断':'人工判断'}</p>
 </div>
 <div data-ng-show="graph.getNode('${this.id}').isAuto()" class="form-group">
    <label class="col-sm-2 control-label">特征类别</label>
    <p class="col-sm-10 form-control-static">${this.name}</p>
 </div>
 <div data-ng-show="graph.getNode('${this.id}').isAuto()" class="form-group">
    <label class="col-sm-2 control-label">特征函数</label>
    <p class="col-sm-10 form-control-static">${this.opertion} ${this.params}</p>
 </div>
 <div data-ng-hide="graph.getNode('${this.id}').isAuto()" class="form-group">
    <label class="col-sm-2 control-label">特征描述</label>
    <p class="col-sm-10 form-control-static">${this.description}</p>
 </div>`
    }

    static loadFeatures() {
        let session = neo4jService.getSession();
        let resultPromise = session.run('MATCH (a:Feature) RETURN a');
        resultPromise.then(result => {
            session.close();
            FeatureNode.features = result.records
                .map((record) => record.get(0))
                .map(node => MyNode.fromNeo4jNode(node));

            FeatureNode.featureTypes = [... new Set(FeatureNode.features.filter(feature => feature.isAuto()).map(feature => feature.name))];

            //TODO Feature 下面的 Component 后续可直接使用loadGraph 中的内容
            FeatureNode.features
            // .filter(feature => feature.isAuto)
                .forEach((feature, index) => {
                    let session2 = neo4jService.getSession();
                    let resultPromise2 = session2.run(`start f=node(${feature.id}) MATCH (f)-[*]->(a:Component) RETURN a`);
                    resultPromise2.then(result => {
                        session2.close();
                        FeatureNode.features[index].components = result.records
                            .map((record) => record.get(0))
                            .map(node => node["identity"].toString());
                    });
                });

            for (let fn of FeatureNode.loadFeatures.callbacks) {
                fn(FeatureNode.features,FeatureNode.featureTypes);
            }
        });
    }

    static loadFeatures2(query,parameters={},...callbacks) {
        let session = neo4jService.getSession();
        let resultPromise = session.run(query,parameters);
        resultPromise.then(result => {
            session.close();
            let features = result.records
                .map((record) => record.get(0))
                .map(node => MyNode.fromNeo4jNode(node));

            let featureTypes = [... new Set(features.filter(feature => feature.isAuto()).map(feature => feature.name))];

            //TODO Feature 下面的 Component 后续可直接使用loadGraph 中的内容
            features
            // .filter(feature => feature.isAuto)
                .forEach((feature, index) => {
                    let session2 = neo4jService.getSession();
                    let resultPromise2 = session2.run(`start f=node(${feature.id}) MATCH (f)-[*]->(a:Component) RETURN a`);
                    resultPromise2.then(result => {
                        session2.close();
                        features[index].components = result.records
                            .map((record) => record.get(0))
                            .map(node => node["identity"].toString());

                        //TODO Callback Here
                        if(index+1==features.length){
                            for (let fn of callbacks) {
                                fn(features,featureTypes);
                            }
                        }
                    });
                });
        });
    }

    getText(){
        let sIndex = '';
        if(this.outId!=0)
            sIndex = `<${this.outId}>`;
        if(this.isAuto())
            return `特征${sIndex}：${this.name} ${this.opertion} ${this.params}`;
        else
            return `特征${sIndex}：${this.description}`;
    }

    getName(){
        if(this.isAuto())
            return `${this.name}`;
        else
            return `${this.description}`;
    }

    getExpression(){
        if(this.isAuto())
            return `${this.name} ${this.opertion} ${this.params}`;
        else
            return `${this.description}`;
    }
}
FeatureNode.loadFeatures.callbacks=[];
// FeatureNode.loadFeatures();
